package yxy.apple.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.Base64;
import java.util.Iterator;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

public class JSONUtility {

	public static final String DefaultEncoding = "UTF-8";

	/*
	 * *****************************JSONObject get value
	 * Method*******************************
	 */
	public static JSONArray getArray(JSONObject json, String key, JSONArray defaultValue) {
		if (json != null && key != null && json.containsKey(key)) {
			return json.getJSONArray(key);
		} else {
			return defaultValue;
		}
	}

	public static boolean getBoolean(JSONObject json, String key, boolean defaultValue) {
		if (json != null && key != null && json.containsKey(key)) {
			return json.getBooleanValue(key);
		} else {
			return defaultValue;
		}
	}

	public static byte[] getBytes(JSONObject json, String key, byte[] defaultValue) {
		if (json != null && key != null && json.containsKey(key)) {
			Object value = json.get(key);
			if (value instanceof byte[]) {
				return (byte[]) value;
			} else if (value instanceof String) {
				return Base64.getDecoder().decode((String) value);
			} else {
				return defaultValue;
			}
		} else {
			return defaultValue;
		}
	}

	@Deprecated
	public static byte[] getBytesBase64(JSONObject json, String key, byte[] defaultValue) {
		if (json != null && key != null && json.containsKey(key)) {
			String string = json.getString(key);
			return Base64.getDecoder().decode(string);
		} else {
			return defaultValue;
		}
	}

	public static double getDouble(JSONObject json, String key, double defaultValue) {
		if (json != null && key != null && json.containsKey(key)) {
			return json.getDoubleValue(key);
		} else {
			return defaultValue;
		}
	}

	public static float getFloat(JSONObject json, String key, float defaultValue) {
		if (json != null && key != null && json.containsKey(key)) {
			return json.getFloatValue(key);
		} else {
			return defaultValue;
		}
	}

	public static int getInt(JSONObject json, String key, int defaultValue) {
		if (json != null && key != null && json.containsKey(key)) {
			return json.getIntValue(key);
		} else {
			return defaultValue;
		}
	}

	public static JSONObject getJSONObject(JSONObject json, String key, JSONObject defaultValue) {
		if (json != null && key != null && json.containsKey(key)) {
			return json.getJSONObject(key);
		} else {
			return defaultValue;
		}
	}

	public static long getLong(JSONObject json, String key, long defaultValue) {
		if (json != null && key != null && json.containsKey(key)) {
			return json.getLongValue(key);
		} else {
			return defaultValue;
		}
	}

	public static short getShort(JSONObject json, String key, short defaultValue) {
		if (json != null && key != null && json.containsKey(key)) {
			return json.getShortValue(key);
		} else {
			return defaultValue;
		}
	}

	public static String getString(JSONObject json, String key, String defaultValue) {
		if (json != null && key != null && json.containsKey(key)) {
			return json.getString(key);
		} else {
			return defaultValue;
		}
	}

	public static Object getObject(JSONObject json, String key, Object defaultValue) {
		if (json != null && key != null && json.containsKey(key)) {
			return json.get(key);
		} else {
			return defaultValue;
		}
	}

	/*
	 * *****************************JSONArray get items method
	 * *******************************
	 */
	public static int getInt(JSONArray array, int index, int defaultValue) {
		if (array != null && array.size() > index) {
			return array.getIntValue(index);
		} else {
			return defaultValue;
		}
	}

	public static JSONObject getJSONObject(JSONArray array, int index, JSONObject defaultValue) {
		if (array != null && array.size() > index) {
			return array.getJSONObject(index);
		} else {
			return defaultValue;
		}
	}

	public static String getString(JSONArray array, int index, String defaultValue) {
		if (array != null && array.size() > index) {
			return array.getString(index);
		} else {
			return defaultValue;
		}
	}

	public static byte[] getBytes(JSONArray array, int index, byte[] defaultValue) {
		if (array != null && array.size() > index) {
			Object value = array.get(index);
			if (value instanceof byte[]) {
				return (byte[]) value;
			} else if (value instanceof String) {
				return Base64.getDecoder().decode((String) value);
			} else {
				return defaultValue;
			}
		} else {
			return defaultValue;
		}
	}

	@Deprecated
	public static byte[] getBytesBase64(JSONArray array, int index, byte[] defaultValue) {
		if (array != null && array.size() > index) {
			String string = array.getString(index);
			return Base64.getDecoder().decode(string);
		} else {
			return defaultValue;
		}
	}

	public static Object getObject(JSONArray array, int index, Object defaultValue) {
		if (array != null && array.size() > index) {
			Object value = array.get(index);
			return value;
		} else {
			return defaultValue;
		}
	}

	/*
	 * *****************************JSONObject vs JSONObject
	 * *******************************
	 */
	/**
	 * 将两个JSONObject合并，destination数据会被source数据中重复的键值覆盖，最终destination被改变
	 * 
	 * @param source
	 * @param destination
	 */
	public static void merge(JSONObject destination, JSONObject source) {
		Iterator<String> keys = source.keySet().iterator();
		while (keys.hasNext()) {
			String key = keys.next();
			Object value = source.get(key);
			destination.remove(key);
			destination.put(key, value);
		}
	}

	/*
	 * *****************************JSONObject Stream
	 * IO*******************************
	 */

	public static JSONObject read(File file) throws IOException {
		return JSONUtility.read(file, DefaultEncoding);
	}

	public static JSONObject read(File file, String encoding) throws IOException {
		FileInputStream fis = new FileInputStream(file);
		JSONObject result = JSONUtility.read(fis, (int) file.length(), encoding);
		fis.close();
		return result;
	}

	public static JSONObject read(InputStream is, int length, String encoding) throws IOException {
		ByteBuffer buffer = ByteBuffer.allocate(length);
		byte[] bytes = new byte[8192];
		int got = is.read(bytes);
		int saved = 0;
		while (got != -1) {
			buffer.put(bytes, 0, got);
			saved += got;
			if (saved >= length) {
				break;
			} else {
				got = is.read(bytes);
			}
		}
		String string = new String(buffer.array(), encoding);
		return JSON.parseObject(string);
	}

	public static void write(JSONObject json, File file, boolean pretty) throws IOException {
		JSONUtility.write(json, file, DefaultEncoding, pretty);
	}

	public static void write(JSONObject json, File file, String encoding, boolean pretty) throws IOException {
		FileOutputStream fos = new FileOutputStream(file);
		JSONUtility.write(json, fos, encoding, pretty);
		fos.flush();
		fos.close();
	}

	public static void write(JSONObject json, OutputStream os, String encoding, boolean pretty) throws IOException {
		String string = JSON.toJSONString(json, pretty);
		byte[] data = string.getBytes(encoding);
		os.write(data);
	}

	public static JSONArray readArray(File file) throws IOException {
		return JSONUtility.readArray(file, DefaultEncoding);
	}

	public static JSONArray readArray(File file, String encoding) throws IOException {
		FileInputStream fis = new FileInputStream(file);
		JSONArray result = JSONUtility.readArray(fis, (int) file.length(), encoding);
		fis.close();
		return result;
	}

	public static JSONArray readArray(InputStream is, int length, String encoding) throws IOException {
		ByteBuffer buffer = ByteBuffer.allocate(length);
		byte[] bytes = new byte[8192];
		int got = is.read(bytes);
		int saved = 0;
		while (got != -1) {
			buffer.put(bytes, 0, got);
			saved += got;
			if (saved >= length) {
				break;
			} else {
				got = is.read(bytes);
			}
		}
		String string = new String(buffer.array(), encoding);
		return JSON.parseArray(string);
	}

	/*
	 * *****************************JSONObject set value
	 * methods*******************************
	 */

	public static boolean setKeyValue(JSONObject json, String key, Object value) {
		if (json != null && key != null && value != null) {
			json.put(key, value);
			return true;
		} else {
			return false;
		}
	}

	public static boolean setArray(JSONObject json, String key, JSONArray value) {
		return setKeyValue(json, key, value);
	}

	public static boolean setBoolean(JSONObject json, String key, boolean value) {
		return setKeyValue(json, key, value);
	}

	public static boolean setBytes(JSONObject json, String key, byte[] bytes) {
		if (bytes != null) {
			return setKeyValue(json, key, bytes);
		} else {
			return false;
		}
	}

	@Deprecated
	public static boolean setBytesBase64(JSONObject json, String key, byte[] bytes) {
		if (bytes != null) {
			String string = Base64.getEncoder().encodeToString(bytes);
			return setKeyValue(json, key, string);
		} else {
			return false;
		}
	}

	public static boolean setDouble(JSONObject json, String key, double value) {
		return setKeyValue(json, key, value);
	}

	public static boolean setFloat(JSONObject json, String key, float value) {
		return setKeyValue(json, key, value);
	}

	public static boolean setInt(JSONObject json, String key, int value) {
		return setKeyValue(json, key, value);
	}

	public static boolean setJSONObject(JSONObject json, String key, JSONObject value) {
		return setKeyValue(json, key, value);
	}

	public static boolean setJSON(JSONObject json, String key, JSON value) {
		return setKeyValue(json, key, value);
	}

	public static void setLong(JSONObject json, String key, long value) {
		json.put(key, value);
	}

	public static boolean setString(JSONObject json, String key, String value) {
		return setKeyValue(json, key, value);
	}

	/*
	 * *****************************JSONArray add value
	 * methods*******************************
	 */

	private static boolean addArrayValue(JSONArray array, Object value) {
		if (array != null && value != null) {
			array.add(value);
			return true;
		} else {
			return false;
		}
	}

	public static boolean addJSON(JSONArray array, JSON value) {
		return addArrayValue(array, value);
	}

	public static boolean addJSONObject(JSONArray array, JSONObject value) {
		return addArrayValue(array, value);
	}

	public static boolean addString(JSONArray array, String value) {
		return addArrayValue(array, value);
	}

	public static boolean addInt(JSONArray array, int value) {
		return addArrayValue(array, value);
	}

	public static boolean addLong(JSONArray array, long value) {
		return addArrayValue(array, value);
	}

	public static boolean addDouble(JSONArray array, double value) {
		return addArrayValue(array, value);
	}

	public static boolean addFloat(JSONArray array, float value) {
		return addArrayValue(array, value);
	}

	public static boolean addBoolean(JSONArray array, boolean value) {
		return addArrayValue(array, value);
	}

	public static boolean addArray(JSONArray array, JSONArray value) {
		return addArrayValue(array, value);
	}

	public static boolean addBytes(JSONArray array, byte[] value) {
		if (value != null) {
			return addArrayValue(array, value);
		} else {
			return false;
		}
	}

	@Deprecated
	public static boolean addBytesBase64(JSONArray array, byte[] value) {
		if (value != null) {
			String string = Base64.getEncoder().encodeToString(value);
			return addArrayValue(array, string);
		} else {
			return false;
		}
	}

}
